package com.esunrising.esungsc.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.esunrising.esungsc.common.utils.ESUNGSCUtil;
import com.esunrising.esungsc.common.utils.HttpUtil;
import com.esunrising.esungsc.dao.FIGLAccountingDocumentDao;
import com.esunrising.esungsc.dto.FIGLZWPZ;
import com.esunrising.esungsc.entity.FIGLAYwdj;
import com.esunrising.esungsc.entity.FIGLAccDocAssistance;
import com.esunrising.esungsc.entity.FIGLAccDocEntry;
import com.esunrising.esungsc.entity.FIGLAccountingDocument;
import com.esunrising.esungsc.service.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
@Slf4j
public class FIGLAccountingDocumentServiceImpl extends BaseServiceImpl<FIGLAccountingDocumentDao,FIGLAccountingDocument> implements FIGLAccountingDocumentService {

    @Resource
    private FIGLAccountingDocumentDao figlAccountingDocumentDao;


    @Resource
    private SysApiUrlService sysApiUrlService;

    @Resource
    private GSCService gscService;

    @Resource
    private FIGLAccDocEntryService figlAccDocEntryService;

    @Resource
    private FIGLAccDocAssistanceService figlAccDocAssistanceService;

    @Resource
    private FIGLAYwdjService figlAYwdjService;

    @Override
    public void syncSave(FIGLAccountingDocument accDoc) {
        // 如果存在，则先删除
        Optional<FIGLAccountingDocument> byId = figlAccountingDocumentDao.findById(accDoc.getID());
        byId.ifPresent( doc -> {
            figlAccountingDocumentDao.deleteById(doc.getID());
        });
        // 保存数据
        super.save(accDoc);
    }

    @Override
    public String voucherList(String dwbh, String orgCode, String kjnd, String sdate, String edate) {
        String orgId = "";
        String ledger = "";
        String type = "pz-test";
        String requestUrl = gscService.getHttpBaseUrl()+sysApiUrlService.findConfigValueByConfigKey(type);
        String responseBody = "";
        int page = 1, // 默认第一页开始
                pageSize = 100, // 默认每页100条数据
                maxPageSize = 1000; // 默认每页获取最大1000条数据
        String msg = "";
        // 取“当前时间”和获取数据范围的“最后时间”中的较小值，作为当前请求后获取到的所有数据的“最后更新时间”
        String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        if(now.compareTo(edate) < 0){
            edate = now;  // 当前日期小于截止日期，则取当前日期
        }

        while(page <= maxPageSize){


            Map<String, Object> bodyParam = new HashMap<>();
            bodyParam.put("year", kjnd);
            bodyParam.put("accorgid", orgCode);
            bodyParam.put("timestamp_lastchangedon", sdate);
            bodyParam.put("endtime", edate);
            bodyParam.put("isfinish", 0);
            bodyParam.put("isbook", 0);
            bodyParam.put("page", page);
            bodyParam.put("num", pageSize);
            // 发送请求
            responseBody = gscService.callGCApi(requestUrl, bodyParam);

            // 根据返回值判断请求情况
            if(!StringUtils.isBlank(responseBody) && responseBody.contains("\"result\":true")){
                if(responseBody.contains("\"FIGLACCOUNTINGDOCUMENT\"")){
                    // 获取成功; 处理结果数据 JSON字符串
                    try {
                        syncAccZWPZList(parseVoucher(responseBody));
                        msg = "获取成功";
                        // 记录日志
                        gscService.saveLog(dwbh, orgId, orgCode, ledger, type, msg);
                        // 更新调用时间记录
                        gscService.updateSyncTime(dwbh, orgId, orgCode, ledger, type, LocalDateTime.now());
                    }catch (Exception e){
                        // 返回值解析失败
                        msg = "返回值解析失败";
                        // 记录日志
                        gscService.saveLog(dwbh, orgId, orgCode, ledger, type, msg);
                        continue;
                    }
                }else{
                    // 接口调用成功，数据为空, 自动退出
                    msg = "获取数据为空, 自动退出";
                    // 记录日志
                    gscService.saveLog(dwbh, orgId, orgCode, ledger, type, msg);
                    // 更新调用时间记录
                    gscService.updateSyncTime(dwbh, orgId, orgCode, ledger, type, LocalDateTime.now());
                }
            }else{
                // 接口调用失败
                msg = "接口调用失败";
                // 记录日志
                gscService.saveLog(dwbh, orgId, orgCode, ledger, type, msg);
                break;
            }
            page++;
        }
        // 记录API全局调用情况
        gscService.updateApiTime(type);

        return msg;
    }

    /**
     * 调用API接口获取GSC账务凭证数据
     * @param year 会计年度
     * @param accOrgID 核算单位编号
     * @param lastChangedOn 获取同步日期；调用方记录获取日期，下次调用传输上次获取日期,获取此日期后的增量数据,格式: yyyy-MM-dd HH:mi:ss
     * @param endTime 插叙能结束时间
     * @param isFinish 是否完成；1-取单据状态为完成状态的凭证, 0-获取全部凭证（不传则默认为0）
     * @param isBook 是否已记账；1-获取已记账凭证, 0-获取全部凭证（不传则默认为1）
     * @param page 页数（默认1）
     * @param num 每页数据量（默认100）
     * @return GSC账务凭证数据
     */
    @Override
    public List<FIGLZWPZ> getApiVoucherList(String year, String accOrgID, String lastChangedOn, String endTime, String isFinish, String isBook, int page, int num){

        String baseUrl = gscService.getHttpBaseUrl();//gscapiConfig.getBaseUrl();
        String getVoucherList = sysApiUrlService.findConfigValueByConfigKey("pz-test");//gscapiConfig.getApis().get("getVoucherList");
        String url = baseUrl + getVoucherList;
        System.out.println(url);
        // 置入Query参数
        String uri = HttpUtil.putQueryParam(url, null);
        // 置入Header参数
        HttpHeaders headers = gscService.getHttpHeaders();
        // 置入Body参数, 这里要用Map而不是MultiValueMap
        /**
         * {
         *     "year": "2024",
         *     "accorgid": "010511",
         *     "timestamp_lastchangedon": "2024-05-09 02:00:48",
         *     "endtime": "2024-05-09 13:44:00",
         *     "page": 1,
         *     "num": 1000,
         *     "isfinish": "0",
         *     "isbook": "0"
         * }
         */

        Map<String, Object> bodyParam = new HashMap<>();
        bodyParam.put("year", year);
        bodyParam.put("accorgid", accOrgID);
        bodyParam.put("timestamp_lastchangedon", lastChangedOn);
        bodyParam.put("endtime", endTime);
        bodyParam.put("isfinish", isFinish);
        bodyParam.put("isbook", isBook);
        bodyParam.put("page", page);
        bodyParam.put("num", num);

        // 发送请求
        String responseBody = gscService.callGCApi(uri, headers, bodyParam);
        // 解析结果
        if(!StringUtils.isBlank(responseBody)){
            // 根据返回值判断请求情况
            if(responseBody.contains("\"result\":true")){
                if(responseBody.contains("\"FIGLACCOUNTINGDOCUMENT\"")){
                    // 获取成功; 处理结果数据 JSON字符串
                    return parseVoucher(responseBody);
                }else{
                    // 接口调用成功，数据为空
                    log.info("获取数据为空, 自动退出");
                    // TODO:记录日志
                    // TODO:更新调用时间记录
                    return null;
                }
            }else{
                // 接口调用失败
                log.error("接口调用失败");
                // TODO:记录日志
                return null;
            }

        }else{
            return null;
        }
    }

    /**
     * 解析GSC账务凭证数据JSON字符串
     * @param jsonStr GSC账务凭证数据JSON字符串
     * @return GSC账务凭证数组
     */
    @Override
    public List<FIGLZWPZ> parseVoucher(String jsonStr) {
        // 解析Json字符串
        JSONObject jsonObject = JSON.parseObject(jsonStr);
        Boolean result = jsonObject.getBoolean("result");
        String code = jsonObject.getString("code");//获取字符串
        if(result){
            log.info("请求凭证数据成功");
            JSONArray value = jsonObject.getJSONArray("value");
            List<FIGLZWPZ> figlzwpzList = new ArrayList<>();
            int countVoucher  = value.size();
            for (int i = 0; i < countVoucher; i++) {
                FIGLZWPZ figlzwpz = new FIGLZWPZ();
                List<FIGLAccDocEntry> accDocEntryList = new ArrayList<>();
                List<FIGLAccDocAssistance> accDocAssList = new ArrayList<>();
                List<FIGLAYwdj> ywdjList = new ArrayList<>();
                JSONObject element = value.getJSONObject(i);
                // 1、解析凭证头
                JSONObject accDocResp = element.getJSONObject("FIGLACCOUNTINGDOCUMENT");

                FIGLAccountingDocument accDoc = ESUNGSCUtil.jsonObject2FIGLAccountingDocument(accDocResp);
                // 加入到accDocList中
                figlzwpz.setAccDoc(accDoc);

                // 2、解析凭证分录
                JSONArray figlaccdocentry = element.getJSONArray("FIGLACCDOCENTRY");
                for(int indexEntry = 0; indexEntry < figlaccdocentry.size(); indexEntry++){
                    JSONObject entry = figlaccdocentry.getJSONObject(indexEntry);
                    FIGLAccDocEntry accDocEntry = ESUNGSCUtil.jsonObject2FIGLAccDocEntry(entry);
                    // 加入到accDocEntryList中
                    accDocEntryList.add(accDocEntry);
                }
                figlzwpz.setAccDocEntryList(accDocEntryList);
                // 3、解析凭证辅助原始
                JSONArray figlaccdocassistance = element.getJSONArray("FIGLACCDOCASSISTANCE");
                for(int indexAss = 0; indexAss < figlaccdocassistance.size(); indexAss++){
                    JSONObject assistance = figlaccdocassistance.getJSONObject(indexAss);
                    FIGLAccDocAssistance accDocAssistance = ESUNGSCUtil.jsonObject2FIGLAccDocAssistance(assistance);
                    // 加入到accDocAssList中
                    accDocAssList.add(accDocAssistance);
                }
                figlzwpz.setAccDocAssList(accDocAssList);
                // 3、解析凭证关联业务单据
                JSONArray figlaywdj = element.getJSONArray("FIGLAYWDJ");
                for(int indexAss = 0; indexAss < figlaywdj.size(); indexAss++){
                    JSONObject ywdjJson = figlaywdj.getJSONObject(indexAss);
                    FIGLAYwdj ywdj = ESUNGSCUtil.jsonObject2FIGLAYwdj(ywdjJson);
                    // 加入到accDocAssList中
                    ywdjList.add(ywdj);
                }
                figlzwpz.setYwdjList(ywdjList);

                //accDocList、accDocEntryList、accDocAssList 转储
                // syncAccZWPZ(figlzwpz);
                figlzwpzList.add(figlzwpz);

            }

            return figlzwpzList;

        }else{
            log.error("请求凭证数据失败");
            return null;
        }
    }

    /**
     * GSC账务凭证存入数据库，包括账务凭证头、账务凭证分录、账务辅助原始;
     * 各部分主键重复的条目采取覆盖的方式
     * @param figlzwpz GSC账务凭证头
     */
    @Override
    public void syncAccZWPZ(FIGLZWPZ figlzwpz) {
        syncAccDocList(List.of(figlzwpz.getAccDoc()));
        figlAccDocEntryService.syncAccDocEntryList(figlzwpz.getAccDocEntryList());
        figlAccDocAssistanceService.syncAccDocAssList(figlzwpz.getAccDocAssList());
        figlAYwdjService.syncFIGLAYwdjList(figlzwpz.getYwdjList());
    }

    /**
     * GSC账务凭证数组存入数据库，包括账务凭证头、账务凭证分录、账务辅助原始;
     * 各部分主键重复的条目采取覆盖的方式
     *
     * @param figlzwpzList GSC账务凭证数组
     */
    @Override
    public void syncAccZWPZList(List<FIGLZWPZ> figlzwpzList) {
        for (FIGLZWPZ figlzwpz : figlzwpzList) {
            syncAccZWPZ(figlzwpz);
        }
    }

    /**
     * GSC账务凭证头数组存入数据库，其中ID重复的会覆盖
     * @param accDocList GSC账务凭证头数组
     */
    @Override
    public void syncAccDocList(List<FIGLAccountingDocument> accDocList){
        for (FIGLAccountingDocument accDoc : accDocList) {
            syncSave(accDoc);
        }
    }


}
